package matImpl;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class Pmat
{
	public static double f(double[] a)
	{
		double res = 0;
		for (int i = 0; i < a.length - 1; i = i + 2)
		{
			res += a[i] * a[i + 1];
		}
		return res;
	}

	public static double g(double[] a, double[] b)
	{
		double res = 0;
		for (int i = 0; i < a.length - 1; i = i + 2)
		{
			res += (a[i] + b[i + 1]) * (a[i + 1] + b[i]);
		}
		return res;
	}
	

	public static double[][] pMult(double[][] a, double[][] b)
	{
		int aLen = a.length;
		double[][] c = new double[aLen][aLen];
		double[] eta = new double[aLen];
		double[] xi = new double[aLen];

		int l = a[0].length - 1;
		for (int r = 0; r < aLen; r++)
		{
			eta[r] = f(a[r]);
			xi[r] = f(b[r]);
		}

		if (a[0].length % 2 == 0)
		{
			for (int i = 0; i < aLen; i++)
			{
				for (int j = 0; j < aLen; j++)
				{
					c[i][j] = g(a[i], b[j]) - eta[i] - xi[j];
				}
			}

		}
		else
		{
			for (int i = 0; i < aLen; i++)
			{
				double[] aa = a[i];
				double[] cc = c[i];
				for (int j = 0; j < aLen; j++)
				{
					cc[j] = g(aa, b[j]) - eta[i] - xi[j] + aa[l] * b[j][l];
				}
			}
		}
		return c;
	}

	public static double[][] pMultMT(final double[][] a, final double[][] b, int threadNumber)
	{

		final int aLen = a.length;
		double[][] c = new double[aLen][aLen];
		final double[] eta = new double[aLen];
		final double[] xi = new double[aLen];

		ExecutorService executor = Executors.newFixedThreadPool(threadNumber);
		final int chunk =threadNumber;

		final int chunkSize = (aLen / chunk <= 0 ? 1 : aLen / chunk);
		final int l = a[0].length - 1;

		for (int x = 0; x < aLen; x = x + chunkSize)
		{
			final int xx = x;
			Runnable r = new Runnable()
			{
				@Override
				public void run()
				{	
					int end=Math.min(xx + chunkSize, aLen);
					for (int r = xx; r < end; r++)
					{
						eta[r] = f(a[r]);
						xi[r] = f(b[r]);
					}

				}
			};
			executor.execute(r);

		}

		int waitTimeInHours = 1;
		try
		{
			executor.shutdown();
			boolean isTerminated = executor.awaitTermination(waitTimeInHours, TimeUnit.HOURS);
			if (!isTerminated)
			{
				System.out.println("Hazard rate generation still ongoing (< " + waitTimeInHours
						+ " hours)");
			}
		}
		catch (InterruptedException ignored)
		{
		}

		ExecutorService executor1 = Executors.newFixedThreadPool(threadNumber);

		if (a[0].length % 2 == 0)
		{
			for (int i = 0; i < aLen; i++)
			{
				final int ii = i;
				final double[] aa = a[i];
				final double[] cc = c[i];

				for (int k = 0; k < aLen; k = k + chunkSize)
				{
					final int start = k;
					Runnable rr = new Runnable()
					{
						@Override
						public void run()
						{
							int end=Math.min(start + chunkSize, aLen);
							for (int j = start; j < end; j++)
							{
								cc[j] = g(aa, b[j]) - eta[ii] - xi[j];
							}

						}
					};
					executor1.execute(rr);

				}
			}

		}
		else
		{

			for (int i = 0; i < aLen; i++)
			{
				final int ii = i;
				final double[] aa = a[i];
				final double[] cc = c[i];

				for (int k = 0; k < aLen; k = k + chunkSize)
				{
					final int start = k;
					Runnable rr = new Runnable()
					{
						@Override
						public void run()
						{
							for (int j = start; j < (start + chunkSize) && j < aLen; j++)
							{
								cc[j] = g(aa, b[j]) - eta[ii] - xi[j] + aa[l] * b[j][l];
							}

						}
					};
					executor1.execute(rr);

				}
			}
		}

		try
		{
			executor1.shutdown();
			boolean isTerminated = executor1.awaitTermination(waitTimeInHours, TimeUnit.HOURS);
			if (!isTerminated)
			{
				System.out.println("Hazard rate generation still ongoing (< " + waitTimeInHours
						+ " hours)");
			}
		}
		catch (InterruptedException ignored)
		{
		}
		return c;
	}

}
